// Copyright  2012 Petr TALLA. [petr.talla@gmail.com]
// This file is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY;  without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
// [http://www.gnu.org/copyleft/lesser.html]
//=============================================================================

package tc.crase.save;

import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

import tc.crase.db.Xattr;
import tc.crase.db.Xobject;
import tc.crase.meta.LinkEstimate;
import tc.common.symbology.Style;
import tc.common.symbology.SymbolItemIregular;
import tc.crase.meta.Type;
import tc.common.symbology.Symbol;
import tc.crase.sys.XdbEx;
import tc.crase.sys.XdbRoot;
import tc.crase.sys.XobjectEx;

public class XdbSave {
	public XdbEx xdb;
	public ObjectNode jsonRoot;
	public ObjectMapper mapper;
	public String status = new String("");
	
	public XdbSave(XdbEx xdb) {
		this.xdb = xdb;
		reset();
	}
	
	public void reset() {
		mapper = null;
		jsonRoot  = null;
	}
	
	public void saveData() {
		saveObjects();
		//saveDocs();
		saveEstimates();
		saveTypes();
		saveSymbols();
		saveLegend();
	}

	public boolean save() {
		mapper = new ObjectMapper();
		jsonRoot  = mapper.createObjectNode();
		
		if (xdb.fileName.isEmpty()) {
			status = "No file specified for this database.";
			return false;
		}
		
		File file = new File(xdb.fileName);
		try {
			file.createNewFile();
		}
		catch (IOException ee) {
			status = "The following file cannot be created: " + xdb.fileName;
			reset();
			return false;
		}
		
		jsonRoot.put("version", 1);
		
		saveData();
		
		try {
			mapper.writeValue(file, jsonRoot);
		}
		catch (Exception ee ) {
			status = "Error writing in file: " + xdb.fileName;
			reset();
			return false;		
		}
		
		reset();
		return true;
	}
	
	private void saveObjects() {
		ArrayNode jsonArray = mapper.createArrayNode();
		jsonRoot.put("objects", jsonArray);
		
		//XdbEx xdbex = XdbRoot.xdbsys.current;
		XdbEx xdbex = (XdbEx)xdb;
			
		Iterator<Xobject> it = xdbex.iterator();
			
		while (it.hasNext()) {
			XobjectEx xobj = (XobjectEx)(it.next());	
			
			ObjectNode userOb = mapper.createObjectNode();
			if (xobj.getId() >= 0) userOb.put("id", xobj.getId());
			ArrayNode jsonArrayAttrs = mapper.createArrayNode();
			userOb.put("attrs", jsonArrayAttrs);
			
			for (Xattr attr : xobj) {
				XdbSaveDb.saveAttr(attr, jsonArrayAttrs, mapper);
			}
			jsonArray.add(userOb);
		}		
	}
	
	/*private void saveDocs() {
		ArrayNode jsonDocs = mapper.createArrayNode();
		jsonRoot.put("docs", jsonDocs);
		
		for ( Doc doc : xdb.getDocs() ) {
			if (doc.getAsGraph() == null) continue;
			
			ObjectNode  jsonDoc  = mapper.createObjectNode();
			jsonDocs.add(jsonDoc);
			jsonDoc.put("type", "GRAPH");
			if (doc.getId() >= 0) jsonDoc.put("id", doc.getId());
			jsonDoc.put("name", doc.name);

			ArrayNode jsonDocArray = mapper.createArrayNode();
			jsonDoc.put("items", jsonDocArray);
			
			DocGraph docg = doc.getAsGraph();
			for (GraphItem item : docg) {
				item.save(jsonDocArray, mapper);
			}
		}
	}*/
	
	private void saveEstimates() {
		ArrayNode jsonEsts = mapper.createArrayNode();
		jsonRoot.put("estimates", jsonEsts);

		for ( int i = 0; i < xdb.metadata.estimates.size(); i++ ) {
			LinkEstimate estimate = xdb.metadata.estimates.get(i);
			
			ObjectNode  jsonEst  = mapper.createObjectNode();
			jsonEsts.add(jsonEst);
			
			jsonEst.put("objectType1", estimate.objectType1);
			jsonEst.put("linkName1",   estimate.linkName1);
			jsonEst.put("objectType2", estimate.objectType2);
			jsonEst.put("linkName2",   estimate.linkName2);
		}
	}
	
	private void saveTypes() {
		ArrayNode jsonTypes = mapper.createArrayNode();
		jsonRoot.put("types", jsonTypes);

		Type[] types = xdb.metadata.types.values().toArray(new Type[0]);

		for ( int i = 0; i < types.length; i++ ) {
			ObjectNode  jsonType  = mapper.createObjectNode();
			jsonTypes.add(jsonType);
			
			types[i].save(jsonType, mapper);
		}
	}
	
	private void saveSymbols() {
		ArrayNode jsonSymbols = mapper.createArrayNode();
		jsonRoot.put("symbols", jsonSymbols);
		Symbol[] symbols = xdb.metadata.legend.symbols.values().toArray(new Symbol[0]);
		
		for ( int i = 0; i < symbols.length; i++ ) {
			ObjectNode  jsonSymbol  = mapper.createObjectNode();
			jsonSymbols.add(jsonSymbol);

			saveSymbol(jsonSymbol, symbols[i]);
		}
	}
	
	private void saveSymbol(ObjectNode jsonSymbol, Symbol symbol) {
		jsonSymbol.put("id", symbol.id);
		
		ArrayNode jsonItems = mapper.createArrayNode();
		jsonSymbol.put("items", jsonItems);
		
		for ( int i = 0; i < symbol.items.size(); i++ ) {
			SymbolItemIregular item = (SymbolItemIregular)symbol.items.get(i);
			
			ObjectNode jsonSitem = mapper.createObjectNode();
			jsonItems.add(jsonSitem);
			
			jsonSitem.put("type",  "IRREGULAR");
			
			if (item.type ==  SymbolItemIregular.Type.LINE) {
				jsonSitem.put("subtype", "line");
			}
			else if (item.type ==  SymbolItemIregular.Type.LINE_CLOSED) {
				jsonSitem.put("subtype", "line_closed");
			}
			else {
				jsonSitem.put("subtype", "area");
			}
			
			jsonSitem.put("red",   item.color.getRed());
			jsonSitem.put("green", item.color.getGreen());
			jsonSitem.put("blue",  item.color.getBlue());
				
			ArrayNode jsonPoints = mapper.createArrayNode();
			jsonSitem.put("points", jsonPoints);
			
			for (int p = 0; p < item.points.size(); p++) {
				Point2D.Double pt = Symbol.createPointStorage(item.points.get(p));
				
				ObjectNode jsonPt = mapper.createObjectNode();
				jsonPoints.add(jsonPt);
				
				jsonPt.put("x", pt.x);
				jsonPt.put("y", pt.y);
			}
		}	
	}
	
	private void saveLegend() {
		ArrayNode jsonStyles = mapper.createArrayNode();
		jsonRoot.put("legend", jsonStyles);
		Style[] styles = xdb.metadata.legend.styles.values().toArray(new Style[0]);
		
		for ( int i = 0; i < styles.length; i++ ) {
			ObjectNode  jsonStyle  = mapper.createObjectNode();
			jsonStyles.add(jsonStyle);

			styles[i].save(jsonStyle, mapper);
		}
	}
}
